package utils

import "sync"

type JobEvent struct {
	Args interface{}
}

// Job 定义了所有托管进程必须实现的接口
type Job interface {
	Execute(args interface{}) // 执行一轮操作
	CondTrigger(e JobEvent) bool
}

// ProcessManager 结构体用于管理多个Job和线程池
type ProcessManager struct {
	jobs       map[string]*managedJob
	jobQueue   chan JobArgs
	wg         sync.WaitGroup
	workersNum int
	mu         sync.RWMutex
}

// managedJob 包含一个Job及其执行状态
type managedJob struct {
	job     Job
	running bool
	cond    *sync.Cond
}

type JobArgs struct {
	job  string
	args interface{}
}

func (mj *managedJob) WaitForJobOver() {
	mj.cond.L.Lock()
	defer mj.cond.L.Unlock()
	for mj.running {
		mj.cond.Wait()
	}
}

// NewProcessManager 创建并返回一个新的ProcessManager实例
func NewProcessManager(workersNum int) *ProcessManager {
	pm := &ProcessManager{
		jobs:       make(map[string]*managedJob),
		jobQueue:   make(chan JobArgs, 100), // 根据需要调整缓冲区大小
		workersNum: workersNum,
	}
	pm.initWorkers()
	return pm
}

// initWorkers 初始化线程池
func (pm *ProcessManager) initWorkers() {
	for i := 0; i < pm.workersNum; i++ {
		go func() {
			for jobArgs := range pm.jobQueue {
				pm.mu.RLock()
				mj, exists := pm.jobs[jobArgs.job]
				if exists && !mj.running {
					mj.running = true
					pm.mu.RUnlock()

					mj.job.Execute(jobArgs.args)

					pm.mu.Lock()
					mj.running = false
					mj.cond.Broadcast()
					pm.mu.Unlock()

					pm.wg.Done()
				} else {
					pm.mu.RUnlock()
				}
			}
		}()
	}
}

// AddJob 添加一个新的Job到ProcessManager中
func (pm *ProcessManager) AddJob(name string, job Job) *managedJob {
	pm.mu.Lock()
	defer pm.mu.Unlock()
	cond := sync.NewCond(&sync.Mutex{})
	pm.jobs[name] = &managedJob{job: job, cond: cond}
	return pm.jobs[name]
}

// RemoveJob 从ProcessManager中移除指定名称的Job
func (pm *ProcessManager) RemoveJob(name string) bool {
	pm.mu.RLock()
	if pm.jobs[name].running {
		pm.mu.RUnlock()
		return false
	} else {
		pm.mu.RUnlock()
		pm.mu.Lock()
		delete(pm.jobs, name)
		pm.mu.Unlock()
		return true
	}
}

// Trigger 触发所有Job执行一轮操作
func (pm *ProcessManager) Trigger(e JobEvent) {
	pm.mu.RLock()
	defer pm.mu.RUnlock()
	for name := range pm.jobs {
		if pm.jobs[name].job.CondTrigger(e) {
			pm.wg.Add(1)
			pm.jobQueue <- JobArgs{name, e.Args} // 将Job的名字放入任务队列
		}
	}
}

func (pm *ProcessManager) WaitForJobOver() {
	pm.wg.Wait()
}

func (pm *ProcessManager) KillWorkers() {
	pm.WaitForJobOver()
	close(pm.jobQueue)
}
